package com.talkyun.openx.server.impl;

import com.talkyun.openx.server.core.Interceptor;
import com.talkyun.openx.server.core.ServiceFactory;
import com.talkyun.utils.Reflector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SimpleServiceFactory implements ServiceFactory {
    private static final Logger logger = LoggerFactory.getLogger(SimpleServiceFactory.class);
    private static SimpleServiceFactory instance = new SimpleServiceFactory();

    private static final Map<String, Object> m2s = new ConcurrentHashMap<String, Object>();
    private static final Map<String, List<Interceptor>> m2i = new ConcurrentHashMap<String, List<Interceptor>>();

    public static ServiceFactory getInstance() {
        return instance;
    }

    private SimpleServiceFactory() {
        // singleton
    }

    @Override
    public Object getService(String mapping) {
        return m2s.get(mapping.toLowerCase());
    }

    @Override
    public List<Interceptor> getInterceptor(String mapping) {
        return m2i.get(mapping.toLowerCase());
    }

    @Override
    public void add(String mapping, Object service) {
        this.add(mapping, new ArrayList<Interceptor>(0), service);
    }

    @Override
    public void add(String mapping, List<Interceptor> list, Object service) {
        // first check
        this.doCheck(Reflector.getInterface(service));
        // last mapping
        String path = mapping.toLowerCase();
        if (!path.startsWith("/")) {
            path = "/" + path;
        }

        ServiceItem item = new ServiceItem(path, mapping, service);
        if (m2s.containsKey(path)) {
            logger.error("Mapping {} is exists! ", path);
        }

        // add service
        logger.info("Openx export {} to {} by {} ", item.getMapping(), item.getPath(), item.getService());
        m2s.put(path, service);
        if (list != null && !list.isEmpty()) {
            m2i.put(path, list);
        }
    }

    private void doCheck(Class<?> clazz) {
        Method[] mths = Reflector.getAllMethod(clazz);
        HashSet<String> set = new HashSet<String>();

        for (Method m : mths) {
            String key = m.getName() + ":" + m.getParameterTypes().length;
            if (set.contains(key)) {
                String msg = clazz.getName() + "." + key + " exists!";
                throw new RuntimeException(msg);
            } else {
                set.add(key);
            }
        }
    }
}